﻿using Colorful.Furniture.CommonDto;
using Colorful.Furniture.Extensions;
using FreeSql;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Services;

namespace Colorful.Furniture.PermissionManagement
{
    /// <summary>
    ///  角色服务
    /// </summary>
    [Authorize]
    public class RoleAppService : ApplicationService
    {
        private readonly IFreeSql _freeSql;
        private readonly ManagerAppService _managerService;
        private readonly IBaseRepository<SysRoleAccess> _sysRoleAccessRepository;
        private readonly IBaseRepository<SysDataPermission> _sysDataPermissionRepository;

        public RoleAppService(IFreeSql freeSql,
            ManagerAppService managerService,
            IBaseRepository<SysRoleAccess> sysRoleAccessRepository,
            IBaseRepository<SysDataPermission> sysDataPermissionRepository)
        {
            _freeSql = freeSql;
            _managerService = managerService;
            _sysRoleAccessRepository = sysRoleAccessRepository;
            _sysDataPermissionRepository = sysDataPermissionRepository;
        }

        /// <summary>
        ///  角色列表
        /// </summary>
        /// <returns></returns>
        public async Task<List<RoleOutputDto>> GetAllListAsync(string keywords)
        {
            var roleOutputList = await _freeSql.Select<SysRole>()
                .Include(x => x.Department)
                .WhereIf(!string.IsNullOrWhiteSpace(keywords), r => r.Name.Contains(keywords))
                .OrderBy(r => r.DepartmentId)
                .ToListAsync(r => new RoleOutputDto
                {
                    Id = r.Id,
                    Name = r.Name,
                    OrganizationId = r.Id,
                    OrganizationName = r.Department.Name,
                    IsDisabled = r.IsDisabled
                });

            return roleOutputList;
        }

        /// <summary>
        ///  角色基础信息
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<RoleOutputDto> GetDetailAsync(Guid id)
        {
            var dto = await _freeSql.Select<SysRole>()
                .Where(x => x.Id == id)
                .ToOneAsync<RoleOutputDto>();

            return dto ?? new RoleOutputDto();
        }

        /// <summary>
        ///  保存角色信息
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<Guid?> PutSaveAsync([FromBody] RoleSaveInputDto input)
        {
            var model = ObjectMapper.Map<RoleSaveInputDto, SysRole>(input);

            //开启事务
            _freeSql.Transaction(() =>
            {
                //修改
                if (!input.Id.IsNull())
                {
                    model = _freeSql.Select<SysRole>()
                        .Where(x => x.Id == input.Id).ToOne();

                    ObjectMapper.Map(input, model);

                    _freeSql.Update<SysRole>()
                        .SetSource(model)
                        .ExecuteAffrows();
                }
                else  //新增
                {
                    model.Id = Guid.NewGuid();
                    model.Code = model.Id.ToString();
                    _freeSql
                        .Insert(model)
                        .ExecuteAffrows();
                }

            });

            await Task.CompletedTask;

            return model.Id;
        }

        /// <summary>
        ///  逻辑删除角色信息（批量删除）
        /// </summary>
        /// <returns></returns>
        public async Task<Guid> DeleteInfoAsync([FromBody] List<Guid?> ids)
        {
            await _freeSql.Delete<SysRole>()
                .Where(x => ids.Contains(x.Id))
                .ExecuteAffrowsAsync();

            return Guid.Empty;
        }

        /// <summary>
        ///  获取角色分配的资源权限树
        /// </summary>
        public async Task<Tuple<List<TreeOutputDto<string>>, List<Guid>>> GetPermissionTreeListAsync(Guid id)
        {
            //获取当前登录的角色编码
            var currentUserRoleIdList = await _managerService.GetRoleListAsync(CurrentUser.Id);

            //当前角色关联的资源和权限
            var resourceWithPermissionList = await _freeSql.Select<SysRoleAccess, SysPermission>()
                .InnerJoin((x, y) => x.PermissionId == y.Id)
                .Where((x, y) => currentUserRoleIdList.Contains(x.RoleId.Value))
                .ToListAsync((x, y) => new
                {
                    x.RoleId,
                    y.ResourceId,
                    PermissionId = y.Id,
                    y.OperationName
                });

            //查询有显示权限的菜单数据
            var resourceGroupList = resourceWithPermissionList
                .Where(x => x.OperationName == "Show")
                .GroupBy(x => new { x.ResourceId })
                .Select(x => new
                {
                    x.Key.ResourceId,
                    PermissionIdList = x.Select(y => y.PermissionId)
                })
                .ToList();

            //查询角色关联的菜单分组去重
            var roleWithResourceGroupIdList = resourceGroupList.Select(x => x.ResourceId).ToList();
            var rolePermissionIdList = resourceWithPermissionList
                .Where(x => x.RoleId == id)
                .GroupBy(x => x.PermissionId)
                .Select(x => x.Key)
                .ToList();

            var resourceOutputList = await _freeSql.Select<SysResource, SysPermission>()
                .LeftJoin((c, b) => b.ResourceId == c.Id)
                .Where((c, b) => c.ResourceType == (int)ResourceType.管理端资源)
                .WhereIf(!CurrentUser.IsInRole("SupperAdmin"), (c, b) => roleWithResourceGroupIdList.Contains(c.Id))
                .ToListAsync((c, b) => new RolePermissionResourceOutputDto
                {
                    OperationTitle = b.OperationTitle,
                    OperationName = b.OperationName,
                    ResourceParentId = c.ParentId,
                    Sort = c.Sort ?? 0,
                    ResourceId = c.Id,
                    ResourceIcon = c.ImgUrl,
                    PermissionId = b.Id,
                    ResourceName = c.Name,
                    ResourceTitle = c.Title
                });

            //权限对应的资源分组列表
            var permissionWithResourceGroupList = resourceOutputList
                .GroupBy(x => new { x.Sort, x.ResourceIcon, x.ResourceId, x.ResourceTitle, x.ResourceParentId, x.ResourceName })
                .Select(x => new ResourceWithPermissionOutputDto
                {
                    ResourceId = x.Key.ResourceId,
                    Sort = x.Key.Sort,
                    ResourceName = x.Key.ResourceName,
                    ResourceIcon = x.Key.ResourceIcon,
                    ResourceTitle = x.Key.ResourceTitle,
                    ResourceParentId = x.Key.ResourceParentId,
                    PermissionList = x.Select(y => new Permission1OutputDto
                    {
                        OperationName = y.OperationName,
                        OperationTitle = y.OperationTitle,
                        PermissionId = y.PermissionId
                    }).ToList()
                }).ToList();

            //通过递归获取菜单树形
            var resourceTreeList = RecursionGetResourceTreeList(permissionWithResourceGroupList, null);

            return Tuple.Create(resourceTreeList, rolePermissionIdList);
        }

        /// <summary>
        ///  获取角色分配的资源权限表格树
        /// </summary>
        /// <returns>item1:资源树+权限列表 item：当前角色对应的资源权限列表</returns>
        public async Task<Tuple<List<ResourceTableTreeOutputDto1>, List<ResourcePermissionOutputDto1>>> GetPermissionTableTreeListAsync(Guid id)
        {
            //获取当前登录的角色编码
            var managerInfo = await _managerService.InfoAsync();
            var currentManagerRoleIdList = managerInfo.RoleList;

            //角色对应的权限编码列表
            var roleResourcePermissionList = await _sysRoleAccessRepository
                .Where(x => x.RoleId == id)
                .Include(x => x.Permission)
                .ToListAsync(x => new ResourcePermissionOutputDto1
                {
                    Id = x.PermissionId,
                    ResourceId = x.Permission.ResourceId,
                    OperationTitle = x.Permission.OperationTitle,
                    OperationName = x.Permission.OperationName
                });

            //查询当前角色的菜单和权限列表数据
            var currentRoleResourcePermissionList = await _freeSql.Select<SysRoleAccess, SysPermission>()
                .InnerJoin((x, y) => x.PermissionId == y.Id)
                .WhereIf(!managerInfo.IsSupper, (x, y) => currentManagerRoleIdList.Contains(x.RoleId.Value))
                .ToListAsync((x, y) => new
                {
                    y.ResourceId
                });
            //角色查看资源编码分组列表
            var roleWithResourceGroupIdList = currentRoleResourcePermissionList
                .Select(x => x.ResourceId)
                .GroupBy(x => x)
                .Select(x => x.Key)
                .ToList();

            //查询资源的所有的权限操作列表（平级）
            var resourceOutputList = await _freeSql.Select<SysResource, SysPermission>()
                .LeftJoin((c, b) => b.ResourceId == c.Id)
                .Where((c, b) => c.ResourceType == (int)ResourceType.管理端资源)
                .WhereIf(!managerInfo.IsSupper, (c, b) => roleWithResourceGroupIdList.Contains(c.Id))
                .ToListAsync((c, b) => new RolePermissionResourceOutputDto
                {
                    OperationTitle = b.OperationTitle,
                    OperationName = b.OperationName,
                    OperationSort = b.OperationSort,
                    ResourceParentId = c.ParentId,

                    PermissionId = b.Id,
                    Sort = c.Sort ?? 0,
                    ResourceId = c.Id,
                    ResourceIcon = c.ImgUrl,
                    ResourceName = c.Name,
                    ResourceTitle = c.Title
                });

            //权限对应的按照资源分组查询权限列表
            var permissionWithResourceGroupList = resourceOutputList
                .GroupBy(x => new { x.Sort, x.ResourceIcon, x.ResourceId, x.ResourceTitle, x.ResourceParentId, x.ResourceName })
                .Select(x => new ResourceTableTreeOutputDto1
                {
                    Id = x.Key.ResourceId,
                    Name = x.Key.ResourceName,
                    IsCheckAll = roleResourcePermissionList.Count(y => y.ResourceId == x.Key.ResourceId) == x.Count(),
                    Sort = x.Key.Sort,
                    Label = x.Key.ResourceTitle,
                    ParentId = x.Key.ResourceParentId,
                    Permissions = x
                        .Where(cc => cc.PermissionId.HasValue)
                        .OrderBy(y => y.OperationSort)
                        .Select(y => new ResourcePermissionOutputDto1
                        {
                            Id = y.PermissionId,
                            OperationTitle = y.OperationTitle,
                            //是否选中
                            IsChecked = roleResourcePermissionList.Any(z => z.Id == y.PermissionId),
                            ResourceId = y.ResourceId
                        }).ToList()
                }).ToList();

            var resourceTree = RecursionGetResourceTableTreeList(permissionWithResourceGroupList, null);

            return Tuple.Create(resourceTree, roleResourcePermissionList);
        }

        /// <summary>
        ///  递归获取资源表格树和权限
        /// </summary>
        /// <returns></returns>
        private static List<ResourceTableTreeOutputDto1> RecursionGetResourceTableTreeList(
            List<ResourceTableTreeOutputDto1> resourceWithPermissionList, Guid? parentId)
        {
            var childrenList = resourceWithPermissionList
                .Where(x => x.ParentId == parentId)
                .OrderBy(x => x.Sort)
                .Select(x =>
                {
                    x.Children = RecursionGetResourceTableTreeList(resourceWithPermissionList, x.Id);

                    return x;

                }).ToList();

            return childrenList;
        }

        /// <summary>
        ///  递归获取资源树和权限
        /// </summary>
        /// <returns></returns>
        private static List<TreeOutputDto<string>> RecursionGetResourceTreeList(
            List<ResourceWithPermissionOutputDto> resourceWithPermissionList, Guid? parentId)
        {
            var childrenList = resourceWithPermissionList
                .Where(x => x.ResourceParentId == parentId)
                .OrderBy(x => x.Sort)
                .Select(x =>
                {
                    //菜单的显示权限
                    var resourceShowPermission = x.PermissionList.FirstOrDefault(z => z.OperationName == "Show");

                    var treeOutput = new TreeOutputDto<string>
                    {
                        //展示菜单的查看权限Id
                        Id = resourceShowPermission?.PermissionId?.ToString(),
                        Icon = string.IsNullOrWhiteSpace(x.ResourceIcon) ? "el-icon-folder" : x.ResourceIcon,
                        Label = x.ResourceTitle
                    };

                    //添加除开显示的权限（上面已添加了）
                    var operationIconList = new Dictionary<string, string>
                    {
                        {"Show","el-icon-circle-check"},
                        {"Add","el-icon-circle-plus-outline"},
                        {"Search","el-icon-search"},
                        {"Delete","el-icon-delete-solid"},
                        {"Audit","el-icon-s-claim"},
                        {"View","el-icon-view"},
                        {"Export","el-icon-folder-opened"},
                        {"Import","el-icon-folder"},
                        {"Edit","el-icon-edit"},
                        {"Submit","el-icon-edit-outline"},
                        {"Set","el-icon-c-scale-to-original"}
                    };
                    treeOutput.Children.AddRange(x.PermissionList
                        .Where(y => y.OperationName != "Show")
                                    .Select(y => new TreeOutputDto<string>
                                    {
                                        Id = y.PermissionId.ToString(),
                                        Icon = !operationIconList.ContainsKey(y.OperationName) ? "el-icon-setting" : operationIconList[y.OperationName],
                                        Label = y.OperationTitle
                                    }));

                    //递归添加菜单部分
                    treeOutput.Children.AddRange(RecursionGetResourceTreeList(resourceWithPermissionList, x.ResourceId));

                    return treeOutput;

                }).ToList();

            return childrenList;
        }

        /// <summary>
        ///  设置角色权限
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<bool> SetPermissionAsync(SetRolePermissionInputDto input)
        {
            //角色对应的权限点集合
            var roleWithPermissionIdList = await _sysRoleAccessRepository
                .Where(x => x.RoleId == input.RoleId)
                .ToListAsync(x => x.PermissionId);

            //传入的角色权限编码分组去重集合
            var inputPermissionIdList = input.PermissionIdList
                .GroupBy(x => x)
                .Select(x => x.Key)
                .ToList();

            using var unitOfWork = _freeSql.CreateUnitOfWork();

            _sysRoleAccessRepository.UnitOfWork = unitOfWork;

            //需要删除的
            var deletePermissionIdList = roleWithPermissionIdList
                .Except(inputPermissionIdList)
                .ToList();

            if (deletePermissionIdList.Any())
                //删除角色赋值的权限列表
                await _sysRoleAccessRepository.DeleteAsync(x => x.RoleId == input.RoleId && deletePermissionIdList.Contains(x.PermissionId));

            //需要新增的
            var sysRoleAccessList = inputPermissionIdList
                .Except(roleWithPermissionIdList)
                .Select(x => new SysRoleAccess
                {
                    Id = Guid.NewGuid(),
                    RoleId = input.RoleId,
                    PermissionId = x
                }).ToList();

            if (sysRoleAccessList.Any())
                await _sysRoleAccessRepository.InsertAsync(sysRoleAccessList);

            unitOfWork.Commit();

            return true;
        }

        /// <summary>
        ///  获取角色对应的数据权限
        /// </summary>
        /// <returns></returns>
        public async Task<RoleDataPermissionOutputDto> GetDataPermissionAsync(Guid id)
        {
            var roleApiRole = await _sysDataPermissionRepository
                .Where(x => x.RoleId == id)
                .FirstAsync();

            if (roleApiRole == null)
                return new RoleDataPermissionOutputDto();

            return new RoleDataPermissionOutputDto
            {
                CrossLevelDepart = roleApiRole.CrossLevelDepart,
                RoleId = id,
                PermissionType = roleApiRole.PermissionType
            };
        }

        /// <summary>
        ///  设置数据权限
        /// </summary>
        /// <returns></returns>
        public async Task<bool> SetDataPermissionAsync(SetRoleDataPermissionInputDto input)
        {
            if ((input.PermissionTypeList.Contains("5") || input.PermissionTypeList.Contains("4")) &&
                string.IsNullOrWhiteSpace(input.CrossLevelDepart))
                throw new UserFriendlyException("请选择跨级的部门", "400");

            using var unitOfWork = _freeSql.CreateUnitOfWork();
            _sysDataPermissionRepository.UnitOfWork = unitOfWork;

            //先删除角色对应的所有数据权限
            await _sysDataPermissionRepository.DeleteAsync(x => x.RoleId == input.RoleId);

            var model = ObjectMapper.Map<SetRoleDataPermissionInputDto, SysDataPermission>(input);

            await _sysDataPermissionRepository.InsertAsync(model);

            unitOfWork.Commit();

            return true;
        }
    }
}